agentmux_srv\backend\history/
mod.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! History module — discovers and indexes past CLI agent conversations from disk.
5
6pub mod adapter;
7pub mod claude_adapter;
8pub mod index;
9
10use std::sync::Arc;
11
12use adapter::*;
13use claude_adapter::ClaudeHistoryAdapter;
14use index::SessionIndex;
15
16/// The history service exposed to the RPC layer.
17pub struct HistoryService {
18    index: Arc<SessionIndex>,
19}
20
21impl HistoryService {
22    pub fn new() -> Self {
23        let adapters: Vec<Box<dyn HistoryAdapter>> =
24            vec![Box::new(ClaudeHistoryAdapter::new())];
25
26        HistoryService {
27            index: Arc::new(SessionIndex::new(adapters)),
28        }
29    }
30
31    /// List sessions with pagination and filters.
32    /// Lazy-initializes the index on first call.
33    pub fn list(
34        &self,
35        provider: Option<&str>,
36        project: Option<&str>,
37        offset: usize,
38        limit: usize,
39        sort_by: &str,
40        sort_dir: &str,
41    ) -> serde_json::Value {
42        // Lazy init: scan on first request
43        if self.index.is_empty() {
44            self.index.refresh();
45        }
46
47        let (sessions, total, has_more) =
48            self.index.list(provider, project, offset, limit, sort_by, sort_dir);
49
50        serde_json::json!({
51            "sessions": sessions,
52            "total": total,
53            "has_more": has_more,
54        })
55    }
56
57    /// Get full conversation for a session.
58    pub fn get(&self, session_id: &str) -> serde_json::Value {
59        // Lazy init
60        if self.index.is_empty() {
61            self.index.refresh();
62        }
63
64        match self.index.get_full(session_id) {
65            Ok(Some(session)) => serde_json::json!({ "session": session }),
66            Ok(None) => serde_json::json!({ "error": "session not found" }),
67            Err(e) => serde_json::json!({ "error": format!("{}", e) }),
68        }
69    }
70
71    /// Re-scan disk and update the index.
72    pub fn refresh(&self) -> serde_json::Value {
73        let (discovered, updated, new_count) = self.index.refresh();
74        serde_json::json!({
75            "discovered": discovered,
76            "updated": updated,
77            "new": new_count,
78        })
79    }
80}